home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 February (DVD) / PCWorld_2008-02_DVD.iso / v cisle / PHP / PHP.exe / xampp-win32-1.6.5-installer.exe / php / PEAR / DB / sqlite.php < prev    next >
Encoding:
PHP Script  |  2007-12-20  |  29.4 KB  |  950 lines

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6.  * The PEAR DB driver for PHP's sqlite extension
  7.  * for interacting with SQLite databases
  8.  *
  9.  * PHP versions 4 and 5
  10.  *
  11.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  12.  * that is available through the world-wide-web at the following URI:
  13.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  14.  * the PHP License and are unable to obtain it through the web, please
  15.  * send a note to license@php.net so we can mail you a copy immediately.
  16.  *
  17.  * @category   Database
  18.  * @package    DB
  19.  * @author     Urs Gehrig <urs@circle.ch>
  20.  * @author     Mika Tuupola <tuupola@appelsiini.net>
  21.  * @author     Daniel Convissor <danielc@php.net>
  22.  * @copyright  1997-2005 The PHP Group
  23.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0 3.0
  24.  * @version    CVS: $Id: sqlite.php,v 1.114 2007/01/12 02:41:07 aharvey Exp $
  25.  * @link       http://pear.php.net/package/DB
  26.  */
  27.  
  28. /**
  29.  * Obtain the DB_common class so it can be extended from
  30.  */
  31. require_once 'DB/common.php';
  32.  
  33. /**
  34.  * The methods PEAR DB uses to interact with PHP's sqlite extension
  35.  * for interacting with SQLite databases
  36.  *
  37.  * These methods overload the ones declared in DB_common.
  38.  *
  39.  * NOTICE:  This driver needs PHP's track_errors ini setting to be on.
  40.  * It is automatically turned on when connecting to the database.
  41.  * Make sure your scripts don't turn it off.
  42.  *
  43.  * @category   Database
  44.  * @package    DB
  45.  * @author     Urs Gehrig <urs@circle.ch>
  46.  * @author     Mika Tuupola <tuupola@appelsiini.net>
  47.  * @author     Daniel Convissor <danielc@php.net>
  48.  * @copyright  1997-2005 The PHP Group
  49.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0 3.0
  50.  * @version    Release: 1.7.9
  51.  * @link       http://pear.php.net/package/DB
  52.  */
  53. class DB_sqlite extends DB_common
  54. {
  55.     // {{{ properties
  56.  
  57.     /**
  58.      * The DB driver type (mysql, oci8, odbc, etc.)
  59.      * @var string
  60.      */
  61.     var $phptype = 'sqlite';
  62.  
  63.     /**
  64.      * The database syntax variant to be used (db2, access, etc.), if any
  65.      * @var string
  66.      */
  67.     var $dbsyntax = 'sqlite';
  68.  
  69.     /**
  70.      * The capabilities of this DB implementation
  71.      *
  72.      * The 'new_link' element contains the PHP version that first provided
  73.      * new_link support for this DBMS.  Contains false if it's unsupported.
  74.      *
  75.      * Meaning of the 'limit' element:
  76.      *   + 'emulate' = emulate with fetch row by number
  77.      *   + 'alter'   = alter the query
  78.      *   + false     = skip rows
  79.      *
  80.      * @var array
  81.      */
  82.     var $features = array(
  83.         'limit'         => 'alter',
  84.         'new_link'      => false,
  85.         'numrows'       => true,
  86.         'pconnect'      => true,
  87.         'prepare'       => false,
  88.         'ssl'           => false,
  89.         'transactions'  => false,
  90.     );
  91.  
  92.     /**
  93.      * A mapping of native error codes to DB error codes
  94.      *
  95.      * {@internal  Error codes according to sqlite_exec.  See the online
  96.      * manual at http://sqlite.org/c_interface.html for info.
  97.      * This error handling based on sqlite_exec is not yet implemented.}}
  98.      *
  99.      * @var array
  100.      */
  101.     var $errorcode_map = array(
  102.     );
  103.  
  104.     /**
  105.      * The raw database connection created by PHP
  106.      * @var resource
  107.      */
  108.     var $connection;
  109.  
  110.     /**
  111.      * The DSN information for connecting to a database
  112.      * @var array
  113.      */
  114.     var $dsn = array();
  115.  
  116.  
  117.     /**
  118.      * SQLite data types
  119.      *
  120.      * @link http://www.sqlite.org/datatypes.html
  121.      *
  122.      * @var array
  123.      */
  124.     var $keywords = array (
  125.         'BLOB'      => '',
  126.         'BOOLEAN'   => '',
  127.         'CHARACTER' => '',
  128.         'CLOB'      => '',
  129.         'FLOAT'     => '',
  130.         'INTEGER'   => '',
  131.         'KEY'       => '',
  132.         'NATIONAL'  => '',
  133.         'NUMERIC'   => '',
  134.         'NVARCHAR'  => '',
  135.         'PRIMARY'   => '',
  136.         'TEXT'      => '',
  137.         'TIMESTAMP' => '',
  138.         'UNIQUE'    => '',
  139.         'VARCHAR'   => '',
  140.         'VARYING'   => '',
  141.     );
  142.  
  143.     /**
  144.      * The most recent error message from $php_errormsg
  145.      * @var string
  146.      * @access private
  147.      */
  148.     var $_lasterror = '';
  149.  
  150.  
  151.     // }}}
  152.     // {{{ constructor
  153.  
  154.     /**
  155.      * This constructor calls <kbd>$this->DB_common()</kbd>
  156.      *
  157.      * @return void
  158.      */
  159.     function DB_sqlite()
  160.     {
  161.         $this->DB_common();
  162.     }
  163.  
  164.     // }}}
  165.     // {{{ connect()
  166.  
  167.     /**
  168.      * Connect to the database server, log in and open the database
  169.      *
  170.      * Don't call this method directly.  Use DB::connect() instead.
  171.      *
  172.      * PEAR DB's sqlite driver supports the following extra DSN options:
  173.      *   + mode  The permissions for the database file, in four digit
  174.      *            chmod octal format (eg "0600").
  175.      *
  176.      * Example of connecting to a database in read-only mode:
  177.      * <code>
  178.      * require_once 'DB.php';
  179.      * 
  180.      * $dsn = 'sqlite:///path/and/name/of/db/file?mode=0400';
  181.      * $options = array(
  182.      *     'portability' => DB_PORTABILITY_ALL,
  183.      * );
  184.      * 
  185.      * $db =& DB::connect($dsn, $options);
  186.      * if (PEAR::isError($db)) {
  187.      *     die($db->getMessage());
  188.      * }
  189.      * </code>
  190.      *
  191.      * @param array $dsn         the data source name
  192.      * @param bool  $persistent  should the connection be persistent?
  193.      *
  194.      * @return int  DB_OK on success. A DB_Error object on failure.
  195.      */
  196.     function connect($dsn, $persistent = false)
  197.     {
  198.         if (!PEAR::loadExtension('sqlite')) {
  199.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  200.         }
  201.  
  202.         $this->dsn = $dsn;
  203.         if ($dsn['dbsyntax']) {
  204.             $this->dbsyntax = $dsn['dbsyntax'];
  205.         }
  206.  
  207.         if (!$dsn['database']) {
  208.             return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION);
  209.         }
  210.  
  211.         if ($dsn['database'] !== ':memory:') {
  212.             if (!file_exists($dsn['database'])) {
  213.                 if (!touch($dsn['database'])) {
  214.                     return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
  215.                 }
  216.                 if (!isset($dsn['mode']) ||
  217.                     !is_numeric($dsn['mode']))
  218.                 {
  219.                     $mode = 0644;
  220.                 } else {
  221.                     $mode = octdec($dsn['mode']);
  222.                 }
  223.                 if (!chmod($dsn['database'], $mode)) {
  224.                     return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
  225.                 }
  226.                 if (!file_exists($dsn['database'])) {
  227.                     return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
  228.                 }
  229.             }
  230.             if (!is_file($dsn['database'])) {
  231.                 return $this->sqliteRaiseError(DB_ERROR_INVALID);
  232.             }
  233.             if (!is_readable($dsn['database'])) {
  234.                 return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION);
  235.             }
  236.         }
  237.  
  238.         $connect_function = $persistent ? 'sqlite_popen' : 'sqlite_open';
  239.  
  240.         // track_errors must remain on for simpleQuery()
  241.         @ini_set('track_errors', 1);
  242.         $php_errormsg = '';
  243.  
  244.         if (!$this->connection = @$connect_function($dsn['database'])) {
  245.             return $this->raiseError(DB_ERROR_NODBSELECTED,
  246.                                      null, null, null,
  247.                                      $php_errormsg);
  248.         }
  249.         return DB_OK;
  250.     }
  251.  
  252.     // }}}
  253.     // {{{ disconnect()
  254.  
  255.     /**
  256.      * Disconnects from the database server
  257.      *
  258.      * @return bool  TRUE on success, FALSE on failure
  259.      */
  260.     function disconnect()
  261.     {
  262.         $ret = @sqlite_close($this->connection);
  263.         $this->connection = null;
  264.         return $ret;
  265.     }
  266.  
  267.     // }}}
  268.     // {{{ simpleQuery()
  269.  
  270.     /**
  271.      * Sends a query to the database server
  272.      *
  273.      * NOTICE:  This method needs PHP's track_errors ini setting to be on.
  274.      * It is automatically turned on when connecting to the database.
  275.      * Make sure your scripts don't turn it off.
  276.      *
  277.      * @param string  the SQL query string
  278.      *
  279.      * @return mixed  + a PHP result resrouce for successful SELECT queries
  280.      *                + the DB_OK constant for other successful queries
  281.      *                + a DB_Error object on failure
  282.      */
  283.     function simpleQuery($query)
  284.     {
  285.         $ismanip = $this->_checkManip($query);
  286.         $this->last_query = $query;
  287.         $query = $this->modifyQuery($query);
  288.  
  289.         $php_errormsg = '';
  290.  
  291.         $result = @sqlite_query($query, $this->connection);
  292.         $this->_lasterror = $php_errormsg ? $php_errormsg : '';
  293.  
  294.         $this->result = $result;
  295.         if (!$this->result) {
  296.             return $this->sqliteRaiseError(null);
  297.         }
  298.  
  299.         // sqlite_query() seems to allways return a resource
  300.         // so cant use that. Using $ismanip instead
  301.         if (!$ismanip) {
  302.             $numRows = $this->numRows($result);
  303.             if (is_object($numRows)) {
  304.                 // we've got PEAR_Error
  305.                 return $numRows;
  306.             }
  307.             return $result;
  308.         }
  309.         return DB_OK;
  310.     }
  311.  
  312.     // }}}
  313.     // {{{ nextResult()
  314.  
  315.     /**
  316.      * Move the internal sqlite result pointer to the next available result
  317.      *
  318.      * @param resource $result  the valid sqlite result resource
  319.      *
  320.      * @return bool  true if a result is available otherwise return false
  321.      */
  322.     function nextResult($result)
  323.     {
  324.         return false;
  325.     }
  326.  
  327.     // }}}
  328.     // {{{ fetchInto()
  329.  
  330.     /**
  331.      * Places a row from the result set into the given array
  332.      *
  333.      * Formating of the array and the data therein are configurable.
  334.      * See DB_result::fetchInto() for more information.
  335.      *
  336.      * This method is not meant to be called directly.  Use
  337.      * DB_result::fetchInto() instead.  It can't be declared "protected"
  338.      * because DB_result is a separate object.
  339.      *
  340.      * @param resource $result    the query result resource
  341.      * @param array    $arr       the referenced array to put the data in
  342.      * @param int      $fetchmode how the resulting array should be indexed
  343.      * @param int      $rownum    the row number to fetch (0 = first row)
  344.      *
  345.      * @return mixed  DB_OK on success, NULL when the end of a result set is
  346.      *                 reached or on failure
  347.      *
  348.      * @see DB_result::fetchInto()
  349.      */
  350.     function fetchInto($result, &$arr, $fetchmode, $rownum = null)
  351.     {
  352.         if ($rownum !== null) {
  353.             if (!@sqlite_seek($this->result, $rownum)) {
  354.                 return null;
  355.             }
  356.         }
  357.         if ($fetchmode & DB_FETCHMODE_ASSOC) {
  358.             $arr = @sqlite_fetch_array($result, SQLITE_ASSOC);
  359.             if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
  360.                 $arr = array_change_key_case($arr, CASE_LOWER);
  361.             }
  362.         } else {
  363.             $arr = @sqlite_fetch_array($result, SQLITE_NUM);
  364.         }
  365.         if (!$arr) {
  366.             return null;
  367.         }
  368.         if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
  369.             /*
  370.              * Even though this DBMS already trims output, we do this because
  371.              * a field might have intentional whitespace at the end that
  372.              * gets removed by DB_PORTABILITY_RTRIM under another driver.
  373.              */
  374.             $this->_rtrimArrayValues($arr);
  375.         }
  376.         if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
  377.             $this->_convertNullArrayValuesToEmpty($arr);
  378.         }
  379.         return DB_OK;
  380.     }
  381.  
  382.     // }}}
  383.     // {{{ freeResult()
  384.  
  385.     /**
  386.      * Deletes the result set and frees the memory occupied by the result set
  387.      *
  388.      * This method is not meant to be called directly.  Use
  389.      * DB_result::free() instead.  It can't be declared "protected"
  390.      * because DB_result is a separate object.
  391.      *
  392.      * @param resource $result  PHP's query result resource
  393.      *
  394.      * @return bool  TRUE on success, FALSE if $result is invalid
  395.      *
  396.      * @see DB_result::free()
  397.      */
  398.     function freeResult(&$result)
  399.     {
  400.         // XXX No native free?
  401.         if (!is_resource($result)) {
  402.             return false;
  403.         }
  404.         $result = null;
  405.         return true;
  406.     }
  407.  
  408.     // }}}
  409.     // {{{ numCols()
  410.  
  411.     /**
  412.      * Gets the number of columns in a result set
  413.      *
  414.      * This method is not meant to be called directly.  Use
  415.      * DB_result::numCols() instead.  It can't be declared "protected"
  416.      * because DB_result is a separate object.
  417.      *
  418.      * @param resource $result  PHP's query result resource
  419.      *
  420.      * @return int  the number of columns.  A DB_Error object on failure.
  421.      *
  422.      * @see DB_result::numCols()
  423.      */
  424.     function numCols($result)
  425.     {
  426.         $cols = @sqlite_num_fields($result);
  427.         if (!$cols) {
  428.             return $this->sqliteRaiseError();
  429.         }
  430.         return $cols;
  431.     }
  432.  
  433.     // }}}
  434.     // {{{ numRows()
  435.  
  436.     /**
  437.      * Gets the number of rows in a result set
  438.      *
  439.      * This method is not meant to be called directly.  Use
  440.      * DB_result::numRows() instead.  It can't be declared "protected"
  441.      * because DB_result is a separate object.
  442.      *
  443.      * @param resource $result  PHP's query result resource
  444.      *
  445.      * @return int  the number of rows.  A DB_Error object on failure.
  446.      *
  447.      * @see DB_result::numRows()
  448.      */
  449.     function numRows($result)
  450.     {
  451.         $rows = @sqlite_num_rows($result);
  452.         if ($rows === null) {
  453.             return $this->sqliteRaiseError();
  454.         }
  455.         return $rows;
  456.     }
  457.  
  458.     // }}}
  459.     // {{{ affected()
  460.  
  461.     /**
  462.      * Determines the number of rows affected by a data maniuplation query
  463.      *
  464.      * 0 is returned for queries that don't manipulate data.
  465.      *
  466.      * @return int  the number of rows.  A DB_Error object on failure.
  467.      */
  468.     function affectedRows()
  469.     {
  470.         return @sqlite_changes($this->connection);
  471.     }
  472.  
  473.     // }}}
  474.     // {{{ dropSequence()
  475.  
  476.     /**
  477.      * Deletes a sequence
  478.      *
  479.      * @param string $seq_name  name of the sequence to be deleted
  480.      *
  481.      * @return int  DB_OK on success.  A DB_Error object on failure.
  482.      *
  483.      * @see DB_common::dropSequence(), DB_common::getSequenceName(),
  484.      *      DB_sqlite::nextID(), DB_sqlite::createSequence()
  485.      */
  486.     function dropSequence($seq_name)
  487.     {
  488.         return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
  489.     }
  490.  
  491.     /**
  492.      * Creates a new sequence
  493.      *
  494.      * @param string $seq_name  name of the new sequence
  495.      *
  496.      * @return int  DB_OK on success.  A DB_Error object on failure.
  497.      *
  498.      * @see DB_common::createSequence(), DB_common::getSequenceName(),
  499.      *      DB_sqlite::nextID(), DB_sqlite::dropSequence()
  500.      */
  501.     function createSequence($seq_name)
  502.     {
  503.         $seqname = $this->getSequenceName($seq_name);
  504.         $query   = 'CREATE TABLE ' . $seqname .
  505.                    ' (id INTEGER UNSIGNED PRIMARY KEY) ';
  506.         $result  = $this->query($query);
  507.         if (DB::isError($result)) {
  508.             return($result);
  509.         }
  510.         $query   = "CREATE TRIGGER ${seqname}_cleanup AFTER INSERT ON $seqname
  511.                     BEGIN
  512.                         DELETE FROM $seqname WHERE id<LAST_INSERT_ROWID();
  513.                     END ";
  514.         $result  = $this->query($query);
  515.         if (DB::isError($result)) {
  516.             return($result);
  517.         }
  518.     }
  519.  
  520.     // }}}
  521.     // {{{ nextId()
  522.  
  523.     /**
  524.      * Returns the next free id in a sequence
  525.      *
  526.      * @param string  $seq_name  name of the sequence
  527.      * @param boolean $ondemand  when true, the seqence is automatically
  528.      *                            created if it does not exist
  529.      *
  530.      * @return int  the next id number in the sequence.
  531.      *               A DB_Error object on failure.
  532.      *
  533.      * @see DB_common::nextID(), DB_common::getSequenceName(),
  534.      *      DB_sqlite::createSequence(), DB_sqlite::dropSequence()
  535.      */
  536.     function nextId($seq_name, $ondemand = true)
  537.     {
  538.         $seqname = $this->getSequenceName($seq_name);
  539.  
  540.         do {
  541.             $repeat = 0;
  542.             $this->pushErrorHandling(PEAR_ERROR_RETURN);
  543.             $result = $this->query("INSERT INTO $seqname (id) VALUES (NULL)");
  544.             $this->popErrorHandling();
  545.             if ($result === DB_OK) {
  546.                 $id = @sqlite_last_insert_rowid($this->connection);
  547.                 if ($id != 0) {
  548.                     return $id;
  549.                 }
  550.             } elseif ($ondemand && DB::isError($result) &&
  551.                       $result->getCode() == DB_ERROR_NOSUCHTABLE)
  552.             {
  553.                 $result = $this->createSequence($seq_name);
  554.                 if (DB::isError($result)) {
  555.                     return $this->raiseError($result);
  556.                 } else {
  557.                     $repeat = 1;
  558.                 }
  559.             }
  560.         } while ($repeat);
  561.  
  562.         return $this->raiseError($result);
  563.     }
  564.  
  565.     // }}}
  566.     // {{{ getDbFileStats()
  567.  
  568.     /**
  569.      * Get the file stats for the current database
  570.      *
  571.      * Possible arguments are dev, ino, mode, nlink, uid, gid, rdev, size,
  572.      * atime, mtime, ctime, blksize, blocks or a numeric key between
  573.      * 0 and 12.
  574.      *
  575.      * @param string $arg  the array key for stats()
  576.      *
  577.      * @return mixed  an array on an unspecified key, integer on a passed
  578.      *                arg and false at a stats error
  579.      */
  580.     function getDbFileStats($arg = '')
  581.     {
  582.         $stats = stat($this->dsn['database']);
  583.         if ($stats == false) {
  584.             return false;
  585.         }
  586.         if (is_array($stats)) {
  587.             if (is_numeric($arg)) {
  588.                 if (((int)$arg <= 12) & ((int)$arg >= 0)) {
  589.                     return false;
  590.                 }
  591.                 return $stats[$arg ];
  592.             }
  593.             if (array_key_exists(trim($arg), $stats)) {
  594.                 return $stats[$arg ];
  595.             }
  596.         }
  597.         return $stats;
  598.     }
  599.  
  600.     // }}}
  601.     // {{{ escapeSimple()
  602.  
  603.     /**
  604.      * Escapes a string according to the current DBMS's standards
  605.      *
  606.      * In SQLite, this makes things safe for inserts/updates, but may
  607.      * cause problems when performing text comparisons against columns
  608.      * containing binary data. See the
  609.      * {@link http://php.net/sqlite_escape_string PHP manual} for more info.
  610.      *
  611.      * @param string $str  the string to be escaped
  612.      *
  613.      * @return string  the escaped string
  614.      *
  615.      * @since Method available since Release 1.6.1
  616.      * @see DB_common::escapeSimple()
  617.      */
  618.     function escapeSimple($str)
  619.     {
  620.         return @sqlite_escape_string($str);
  621.     }
  622.  
  623.     // }}}
  624.     // {{{ modifyLimitQuery()
  625.  
  626.     /**
  627.      * Adds LIMIT clauses to a query string according to current DBMS standards
  628.      *
  629.      * @param string $query   the query to modify
  630.      * @param int    $from    the row to start to fetching (0 = the first row)
  631.      * @param int    $count   the numbers of rows to fetch
  632.      * @param mixed  $params  array, string or numeric data to be used in
  633.      *                         execution of the statement.  Quantity of items
  634.      *                         passed must match quantity of placeholders in
  635.      *                         query:  meaning 1 placeholder for non-array
  636.      *                         parameters or 1 placeholder per array element.
  637.      *
  638.      * @return string  the query string with LIMIT clauses added
  639.      *
  640.      * @access protected
  641.      */
  642.     function modifyLimitQuery($query, $from, $count, $params = array())
  643.     {
  644.         return "$query LIMIT $count OFFSET $from";
  645.     }
  646.  
  647.     // }}}
  648.     // {{{ modifyQuery()
  649.  
  650.     /**
  651.      * Changes a query string for various DBMS specific reasons
  652.      *
  653.      * This little hack lets you know how many rows were deleted
  654.      * when running a "DELETE FROM table" query.  Only implemented
  655.      * if the DB_PORTABILITY_DELETE_COUNT portability option is on.
  656.      *
  657.      * @param string $query  the query string to modify
  658.      *
  659.      * @return string  the modified query string
  660.      *
  661.      * @access protected
  662.      * @see DB_common::setOption()
  663.      */
  664.     function modifyQuery($query)
  665.     {
  666.         if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) {
  667.             if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) {
  668.                 $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
  669.                                       'DELETE FROM \1 WHERE 1=1', $query);
  670.             }
  671.         }
  672.         return $query;
  673.     }
  674.  
  675.     // }}}
  676.     // {{{ sqliteRaiseError()
  677.  
  678.     /**
  679.      * Produces a DB_Error object regarding the current problem
  680.      *
  681.      * @param int $errno  if the error is being manually raised pass a
  682.      *                     DB_ERROR* constant here.  If this isn't passed
  683.      *                     the error information gathered from the DBMS.
  684.      *
  685.      * @return object  the DB_Error object
  686.      *
  687.      * @see DB_common::raiseError(),
  688.      *      DB_sqlite::errorNative(), DB_sqlite::errorCode()
  689.      */
  690.     function sqliteRaiseError($errno = null)
  691.     {
  692.         $native = $this->errorNative();
  693.         if ($errno === null) {
  694.             $errno = $this->errorCode($native);
  695.         }
  696.  
  697.         $errorcode = @sqlite_last_error($this->connection);
  698.         $userinfo = "$errorcode ** $this->last_query";
  699.  
  700.         return $this->raiseError($errno, null, null, $userinfo, $native);
  701.     }
  702.  
  703.     // }}}
  704.     // {{{ errorNative()
  705.  
  706.     /**
  707.      * Gets the DBMS' native error message produced by the last query
  708.      *
  709.      * {@internal This is used to retrieve more meaningfull error messages
  710.      * because sqlite_last_error() does not provide adequate info.}}
  711.      *
  712.      * @return string  the DBMS' error message
  713.      */
  714.     function errorNative()
  715.     {
  716.         return $this->_lasterror;
  717.     }
  718.  
  719.     // }}}
  720.     // {{{ errorCode()
  721.  
  722.     /**
  723.      * Determines PEAR::DB error code from the database's text error message
  724.      *
  725.      * @param string $errormsg  the error message returned from the database
  726.      *
  727.      * @return integer  the DB error number
  728.      */
  729.     function errorCode($errormsg)
  730.     {
  731.         static $error_regexps;
  732.         
  733.         // PHP 5.2+ prepends the function name to $php_errormsg, so we need
  734.         // this hack to work around it, per bug #9599.
  735.         $errormsg = preg_replace('/^sqlite[a-z_]+\(\): /', '', $errormsg);
  736.         
  737.         if (!isset($error_regexps)) {
  738.             $error_regexps = array(
  739.                 '/^no such table:/' => DB_ERROR_NOSUCHTABLE,
  740.                 '/^no such index:/' => DB_ERROR_NOT_FOUND,
  741.                 '/^(table|index) .* already exists$/' => DB_ERROR_ALREADY_EXISTS,
  742.                 '/PRIMARY KEY must be unique/i' => DB_ERROR_CONSTRAINT,
  743.                 '/is not unique/' => DB_ERROR_CONSTRAINT,
  744.                 '/columns .* are not unique/i' => DB_ERROR_CONSTRAINT,
  745.                 '/uniqueness constraint failed/' => DB_ERROR_CONSTRAINT,
  746.                 '/may not be NULL/' => DB_ERROR_CONSTRAINT_NOT_NULL,
  747.                 '/^no such column:/' => DB_ERROR_NOSUCHFIELD,
  748.                 '/column not present in both tables/i' => DB_ERROR_NOSUCHFIELD,
  749.                 '/^near ".*": syntax error$/' => DB_ERROR_SYNTAX,
  750.                 '/[0-9]+ values for [0-9]+ columns/i' => DB_ERROR_VALUE_COUNT_ON_ROW,
  751.             );
  752.         }
  753.         foreach ($error_regexps as $regexp => $code) {
  754.             if (preg_match($regexp, $errormsg)) {
  755.                 return $code;
  756.             }
  757.         }
  758.         // Fall back to DB_ERROR if there was no mapping.
  759.         return DB_ERROR;
  760.     }
  761.  
  762.     // }}}
  763.     // {{{ tableInfo()
  764.  
  765.     /**
  766.      * Returns information about a table
  767.      *
  768.      * @param string         $result  a string containing the name of a table
  769.      * @param int            $mode    a valid tableInfo mode
  770.      *
  771.      * @return array  an associative array with the information requested.
  772.      *                 A DB_Error object on failure.
  773.      *
  774.      * @see DB_common::tableInfo()
  775.      * @since Method available since Release 1.7.0
  776.      */
  777.     function tableInfo($result, $mode = null)
  778.     {
  779.         if (is_string($result)) {
  780.             /*
  781.              * Probably received a table name.
  782.              * Create a result resource identifier.
  783.              */
  784.             $id = @sqlite_array_query($this->connection,
  785.                                       "PRAGMA table_info('$result');",
  786.                                       SQLITE_ASSOC);
  787.             $got_string = true;
  788.         } else {
  789.             $this->last_query = '';
  790.             return $this->raiseError(DB_ERROR_NOT_CAPABLE, null, null, null,
  791.                                      'This DBMS can not obtain tableInfo' .
  792.                                      ' from result sets');
  793.         }
  794.  
  795.         if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
  796.             $case_func = 'strtolower';
  797.         } else {
  798.             $case_func = 'strval';
  799.         }
  800.  
  801.         $count = count($id);
  802.         $res   = array();
  803.  
  804.         if ($mode) {
  805.             $res['num_fields'] = $count;
  806.         }
  807.  
  808.         for ($i = 0; $i < $count; $i++) {
  809.             if (strpos($id[$i]['type'], '(') !== false) {
  810.                 $bits = explode('(', $id[$i]['type']);
  811.                 $type = $bits[0];
  812.                 $len  = rtrim($bits[1],')');
  813.             } else {
  814.                 $type = $id[$i]['type'];
  815.                 $len  = 0;
  816.             }
  817.  
  818.             $flags = '';
  819.             if ($id[$i]['pk']) {
  820.                 $flags .= 'primary_key ';
  821.             }
  822.             if ($id[$i]['notnull']) {
  823.                 $flags .= 'not_null ';
  824.             }
  825.             if ($id[$i]['dflt_value'] !== null) {
  826.                 $flags .= 'default_' . rawurlencode($id[$i]['dflt_value']);
  827.             }
  828.             $flags = trim($flags);
  829.  
  830.             $res[$i] = array(
  831.                 'table' => $case_func($result),
  832.                 'name'  => $case_func($id[$i]['name']),
  833.                 'type'  => $type,
  834.                 'len'   => $len,
  835.                 'flags' => $flags,
  836.             );
  837.  
  838.             if ($mode & DB_TABLEINFO_ORDER) {
  839.                 $res['order'][$res[$i]['name']] = $i;
  840.             }
  841.             if ($mode & DB_TABLEINFO_ORDERTABLE) {
  842.                 $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  843.             }
  844.         }
  845.  
  846.         return $res;
  847.     }
  848.  
  849.     // }}}
  850.     // {{{ getSpecialQuery()
  851.  
  852.     /**
  853.      * Obtains the query string needed for listing a given type of objects
  854.      *
  855.      * @param string $type  the kind of objects you want to retrieve
  856.      * @param array  $args  SQLITE DRIVER ONLY: a private array of arguments
  857.      *                       used by the getSpecialQuery().  Do not use
  858.      *                       this directly.
  859.      *
  860.      * @return string  the SQL query string or null if the driver doesn't
  861.      *                  support the object type requested
  862.      *
  863.      * @access protected
  864.      * @see DB_common::getListOf()
  865.      */
  866.     function getSpecialQuery($type, $args = array())
  867.     {
  868.         if (!is_array($args)) {
  869.             return $this->raiseError('no key specified', null, null, null,
  870.                                      'Argument has to be an array.');
  871.         }
  872.  
  873.         switch ($type) {
  874.             case 'master':
  875.                 return 'SELECT * FROM sqlite_master;';
  876.             case 'tables':
  877.                 return "SELECT name FROM sqlite_master WHERE type='table' "
  878.                        . 'UNION ALL SELECT name FROM sqlite_temp_master '
  879.                        . "WHERE type='table' ORDER BY name;";
  880.             case 'schema':
  881.                 return 'SELECT sql FROM (SELECT * FROM sqlite_master '
  882.                        . 'UNION ALL SELECT * FROM sqlite_temp_master) '
  883.                        . "WHERE type!='meta' "
  884.                        . 'ORDER BY tbl_name, type DESC, name;';
  885.             case 'schemax':
  886.             case 'schema_x':
  887.                 /*
  888.                  * Use like:
  889.                  * $res = $db->query($db->getSpecialQuery('schema_x',
  890.                  *                   array('table' => 'table3')));
  891.                  */
  892.                 return 'SELECT sql FROM (SELECT * FROM sqlite_master '
  893.                        . 'UNION ALL SELECT * FROM sqlite_temp_master) '
  894.                        . "WHERE tbl_name LIKE '{$args['table']}' "
  895.                        . "AND type!='meta' "
  896.                        . 'ORDER BY type DESC, name;';
  897.             case 'alter':
  898.                 /*
  899.                  * SQLite does not support ALTER TABLE; this is a helper query
  900.                  * to handle this. 'table' represents the table name, 'rows'
  901.                  * the news rows to create, 'save' the row(s) to keep _with_
  902.                  * the data.
  903.                  *
  904.                  * Use like:
  905.                  * $args = array(
  906.                  *     'table' => $table,
  907.                  *     'rows'  => "id INTEGER PRIMARY KEY, firstname TEXT, surname TEXT, datetime TEXT",
  908.                  *     'save'  => "NULL, titel, content, datetime"
  909.                  * );
  910.                  * $res = $db->query( $db->getSpecialQuery('alter', $args));
  911.                  */
  912.                 $rows = strtr($args['rows'], $this->keywords);
  913.  
  914.                 $q = array(
  915.                     'BEGIN TRANSACTION',
  916.                     "CREATE TEMPORARY TABLE {$args['table']}_backup ({$args['rows']})",
  917.                     "INSERT INTO {$args['table']}_backup SELECT {$args['save']} FROM {$args['table']}",
  918.                     "DROP TABLE {$args['table']}",
  919.                     "CREATE TABLE {$args['table']} ({$args['rows']})",
  920.                     "INSERT INTO {$args['table']} SELECT {$rows} FROM {$args['table']}_backup",
  921.                     "DROP TABLE {$args['table']}_backup",
  922.                     'COMMIT',
  923.                 );
  924.  
  925.                 /*
  926.                  * This is a dirty hack, since the above query will not get
  927.                  * executed with a single query call so here the query method
  928.                  * will be called directly and return a select instead.
  929.                  */
  930.                 foreach ($q as $query) {
  931.                     $this->query($query);
  932.                 }
  933.                 return "SELECT * FROM {$args['table']};";
  934.             default:
  935.                 return null;
  936.         }
  937.     }
  938.  
  939.     // }}}
  940. }
  941.  
  942. /*
  943.  * Local variables:
  944.  * tab-width: 4
  945.  * c-basic-offset: 4
  946.  * End:
  947.  */
  948.  
  949. ?>
  950.